#include "iostream"
#include "opencv2/opencv.hpp"
#include "opencv2/highgui.hpp"

#ifndef IMAGE_CATCHER_H
#define IMAGE_CATCHER_H

using namespace cv;
using namespace std;

class ImageCatcher
{
private:
    int width, height;
	char pixelFormat[4]{};
    Mat frame;
	char outputFilename[100]{};
	const char *getFilename();
	VideoCapture capture;
public:
    ImageCatcher(int deviceID, int width, int height, const char pixelFormat[]);
    ~ImageCatcher();
    Mat& getFrame();
    void showVideoStream();
	static void showVideoStream(ImageCatcher& imageCatcher);
	static void showFrame(Mat &frame, int scale, const char *winName);
	int getWidth() const;
	void setWidth(int width);
	int getHeight() const;
	void setHeight(int height);
	void setFilename(const char filename[]);
};

ImageCatcher::ImageCatcher(int deviceID, int width, int height, const char pixelFormat[])
{
    this->width = width;
    this->height = height;
    capture = cv::VideoCapture(deviceID);
    capture.set(CAP_PROP_FRAME_WIDTH, width);
	capture.set(CAP_PROP_FRAME_HEIGHT, height);
    
    if (strcmp(pixelFormat, "MJPG") == 0) {
        capture.set(CAP_PROP_FOURCC, VideoWriter::fourcc('M', 'J', 'P', 'G'));
    } else if (strcmp(pixelFormat, "YUYV") == 0) {
        capture.set(CAP_PROP_FOURCC, VideoWriter::fourcc('Y', 'U', 'Y', 'V'));
    }
	strcpy(ImageCatcher::pixelFormat, pixelFormat);
}

Mat& ImageCatcher::getFrame() {
	if (!capture.isOpened()) {
		cerr << "video capture not opened." << endl;
	}
    capture.read(frame);
    return frame;
}

void ImageCatcher::setFilename(const char filename[]) {
	strcpy(outputFilename, filename);
}

void ImageCatcher::showVideoStream() {
    showVideoStream(*this);
}

void ImageCatcher::showVideoStream(ImageCatcher& imageCatcher) {
	int width = imageCatcher.getWidth();
	int height = imageCatcher.getHeight();
	int count = 0;
	while (true)
	{
		Mat frame = imageCatcher.getFrame();
		if (frame.empty()) {
			cout << "Empty frame." << endl;
			continue;
		}
		int key = waitKey(1);
		Mat zoommin;
		resize(frame, zoommin, Size(width/2, height/2), 0, 0, INTER_LINEAR);
		imshow("video", zoommin);

		if (key == 27) {
			break;
		}

		if (key == 32) {
			char* filename = new char[110];
			sprintf(filename, "./%s%d.jpg", imageCatcher.getFilename(), ++count);
			imwrite(filename, frame);
			imshow("image", frame);
			delete[] filename;
		}
	}
}

void ImageCatcher::showFrame(Mat &frame, int scale, const char *winName) {
	Mat zoommin;
	resize(frame, zoommin, Size(frame.cols/scale, frame.rows/scale), 0, 0, INTER_LINEAR);
	imshow(winName, zoommin);
}

ImageCatcher::~ImageCatcher()
= default;

int ImageCatcher::getWidth() const {
	return width;
}

void ImageCatcher::setWidth(int width) {
	ImageCatcher::width = width;
}

int ImageCatcher::getHeight() const {
	return height;
}

void ImageCatcher::setHeight(int height) {
	ImageCatcher::height = height;
}

const char *ImageCatcher::getFilename() {
	return outputFilename;
}


#endif //IMAGE_CATCHER_H